
#include "sock.hpp"
#include <functional>
#include <poll.h>


namespace mypoll
{
static const int defaultport=8080;
static const int defaultfd=-1;
static const int num=1024;

using func_t=std::function<std::string (const std::string&)>;

class PollServer{

    public:
        PollServer(func_t func,int port=defaultport):_port(port),_listensock(-1),_rfds(nullptr),_func(func){}

        void initServer(){
            _listensock=sock::Socket();
            sock::Bind(_listensock,_port);    
            sock::Listen(_listensock);
            _rfds=new struct pollfd[num];
            for(int i=0;i<num;++i) ResetItem(i);
            _rfds[0].fd=_listensock;
            _rfds[0].events=POLLIN;
        }
        void ResetItem(int pos){
            _rfds[pos].fd=defaultfd;
            _rfds[pos].events=0;
            _rfds[pos].revents=0;
        }
        void Print(){
            for(int i=0;i<num;++i){
                if(_rfds[i].fd!=defaultfd){
                    std::cout<<_rfds[i].fd<<" ";
                }
            }
            std::cout<<endl;
        }

        void Accepter(){
            std::string clientip;
            uint16_t clientport=0;
            int sock=sock::Accept(_listensock,&clientip,&clientport);
            if(sock<0){
                return;
            }
            logMessage(NORMAL, "accept success [%s:%d]", clientip.c_str(), clientport);
            // sock我们能直接recv/read 吗？不能，整个代码，只有select有资格检测事件是否就绪
            // 将新的sock 托管给select！
            // 将新的sock托管给select的本质，其实就是将sock，添加到fdarray数组中即可！
            int i=0;
            for(;i<num;++i){
                if(_rfds[i].fd!=defaultfd) continue;
                else break;
            }
            if(i==num){
                logMessage(WARNING,"server if full,please wait");
                close(sock);
            }else{
                _rfds[i].fd=sock;
                _rfds[i].events=POLLIN;
                _rfds[i].revents=0;
            }
            Print();
        }

        void Recver(int pos){
            // 1. 读取request
            // 这样读取是有问题的！--现在姑且这样处理
            char buff[1024];
            ssize_t s=recv(_rfds[pos].fd,buff,sizeof(buff)-1,0);//在这里进行读取的时候，是不会被阻塞的
            if(s>0){
                buff[s]=0;
                logMessage(NORMAL,"client# %s",buff);
            }else if(s==0){
                close(_rfds[pos].fd);
                ResetItem(pos);
                logMessage(NORMAL,"client quit");
                return;
            }else{
                close(_rfds[pos].fd);
                ResetItem(pos);
                logMessage(ERROR,"client quit: %s",strerror(errno));
                return;
            }
            //2. 处理request
            std::string respone=_func(buff);
            //3.返回response
            //这里这样处理也是有bug的
            write(_rfds[pos].fd,respone.c_str(),respone.size());
        }

       // 1. handler event rfds 中，不仅仅是有一个fd是就绪的，可能存在多个
        void HandlerEvent(){
            for(int i=0;i<num;++i){
                //过滤非法的fd
                if(_rfds[i].fd==defaultfd || !_rfds[i].events & POLLIN) continue;
                //正常的fd
                if(_rfds[i].fd==_listensock && (_rfds[i].revents & POLLIN))
                    Accepter();
                else if(_rfds[i].revents & POLLIN)
                    Recver(i);
                else {}
                    //....
            }
        }

        void start(){
            for(;;){
                int timeout=-1;
                int n=poll(_rfds,num,timeout);
                switch(n){
                    case 0:
                        logMessage(NORMAL,"timeout....");
                        break;
                    case -1:
                        logMessage(WARNING,"select error,code %d ,err string %s",errno,strerror(errno));
                        break;
                    default:
                        logMessage(NORMAL,"get a new link...");
                        HandlerEvent();
                        break;
                }

            }
        }

        ~PollServer(){
            if(_listensock>0)
                close(_listensock);
            if(_rfds)
                delete[]_rfds;
        }
    private:
        int _port;
        int _listensock;
        struct pollfd* _rfds;
        func_t _func;
};

}

